package com.momo.mal.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;


import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.momo.mal.Login;
import com.momo.mal.entity.Anime;
import com.momo.mal.entity.Manga;

import android.content.Context;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.os.Environment;
import android.util.Base64;
import android.util.Log;
import android.widget.Toast;

/**
 * @author Dias Nurul Arifin
 * 
 */
public class ConnectionUtil {

	public static final String API_HOST = "http://myanimelist.net/";
	public static final String API_HOST_UPDATE_ANIME = "http://myanimelist.net/api/animelist/update/";
	public static final String API_HOST_UPDATE_MANGA = "http://myanimelist.net/api/mangalist/update/";
	public static final String API_HOST_ADD_ANIME = "http://myanimelist.net/api/animelist/add/";
	public static final String API_HOST_ADD_MANGA = "http://myanimelist.net/api/mangalist/add/";
	public static final String SECONDATY_API_HOST = "http://mal-api.com/";
	public static final String RSS_MANGA = "http://myanimelist.net/rss.php?type=rm&u=";
	public static final String RSS_ANIME = "http://myanimelist.net/rss.php?type=rw&u=";
	public static final String CACHE_PATH = "Android" + File.separator + "data" + File.separator + "com.momo.mal" + File.separator + "cache";
	
	public static boolean postUpdateXML(Anime anime, Manga manga, Context context, String urlAPI) throws IOException {
		SharedPreferences settings = context.getSharedPreferences(Login.PREFS_NAME,
				Context.MODE_PRIVATE);
		
		String userPass = settings.getString("username", "") + ":" + settings.getString("password", "");
		String encodedAuthorization = Base64.encodeToString(userPass.getBytes(), 0);
		
		boolean valid = false;
		String id = anime != null ? anime.getId() : manga.getId();
		URL url = new URL(urlAPI + id + ".xml");
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setConnectTimeout(15000);
		connection.setDoOutput(true);
		connection.setRequestMethod("POST");
		connection.setRequestProperty("Authorization", "Basic " + encodedAuthorization);
		
		String data = anime != null ? convertAnimeToXML(anime) : convertMangaToXML(manga);
		OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
		writer.write("data=" + data);
		writer.close();
		
		if(connection.getResponseCode() == HttpStatus.SC_OK) {
			valid = true;
		} else {
			valid = false;
		}
		
		return valid;
	}
	
	public static boolean postAddXML(Anime anime, Manga manga, Context context, String urlAPI) throws IOException {
		SharedPreferences settings = context.getSharedPreferences(Login.PREFS_NAME,
				Context.MODE_PRIVATE);
		
		String userPass = settings.getString("username", "") + ":" + settings.getString("password", "");
		String encodedAuthorization = Base64.encodeToString(userPass.getBytes(), 0);
		
		boolean valid = false;
		String id = anime != null ? anime.getId() : manga.getId();
		URL url = new URL(urlAPI + id + ".xml");
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setConnectTimeout(15000);
		connection.setDoOutput(true);
		connection.setRequestMethod("POST");
		connection.setRequestProperty("Authorization", "Basic " + encodedAuthorization);
		
		String data = anime != null ? convertAnimeToXML(anime) : convertMangaToXML(manga);
		OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
		writer.write("data=" + data);
		writer.close();
		
		if(connection.getResponseCode() == HttpStatus.SC_CREATED) {
			valid = true;
		} else {
			valid = false;
		}
		return valid;
	}
	
	public static boolean postDeleteXML(String url, Context context) throws ClientProtocolException, IOException {
		DefaultHttpClient httpClient = new DefaultHttpClient(getHttpParams(15000, 15000));
		SharedPreferences settings = context.getSharedPreferences(Login.PREFS_NAME,
				Context.MODE_PRIVATE);
		
		String username = settings.getString("username", "");
		String password = settings.getString("password", "");
		httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY,
				new UsernamePasswordCredentials(username, password));
		
		HttpPost httpPost = new HttpPost(url);
		httpPost.setHeader("Content-Type", "application/xml");
		httpPost.addHeader("Accept", "application/xml");
			
		HttpResponse response = httpClient.execute(httpPost);
		if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && convertEntityToString(response.getEntity()).equalsIgnoreCase("deleted")) {
			return true;
		} else {
			return false;
		}
		
	}

	public static JSONObject get(String url, Context context) throws JSONException, IOException {
		JSONObject json = null;
		HttpClient httpClient = new DefaultHttpClient(getHttpParams(15000,
				15000));
		HttpGet httpGet = new HttpGet(url);
		httpGet.setHeader("Content-Type", "application/json");
		HttpResponse response = httpClient.execute(httpGet);
		if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			json = new JSONObject(convertEntityToString(response.getEntity()));
		}
		return json;
	}

	public static JSONObject post(String url, List<NameValuePair> nameValuePairs, Context context) throws JSONException, IOException {
		JSONObject json = new JSONObject();
		HttpClient httpClient = new DefaultHttpClient();
		HttpPost httpPost = new HttpPost(url);
		httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
		HttpResponse response = httpClient.execute(httpPost);
		if (response != null) {
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				json = new JSONObject(
						convertEntityToString(response.getEntity()));
				json.put("response", "success");
			} else {
				json.put("response", "failed");
			}
		} else {
			json.put("response", "failed");
		}
		return json;
	}
	
	public static boolean login(String username, String password) {
		DefaultHttpClient httpclient = new DefaultHttpClient();

		httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY,
				new UsernamePasswordCredentials(username, password));

		HttpGet httpGet = new HttpGet(API_HOST
				+ "api/account/verify_credentials.xml");
		
		
		try {
			HttpResponse response = httpclient.execute(httpGet);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
				return true;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return false;
	}

	public static JSONObject getSearch(String url) throws JSONException, IOException {
		JSONObject json = null;
		HttpClient httpClient = new DefaultHttpClient(getHttpParams(15000,
				15000));
		HttpGet httpGet = new HttpGet(url);
			httpGet.setHeader("Content-Type", "text/plain");
			HttpResponse response = httpClient.execute(httpGet);
			if (response != null) {
				if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
					String getString = "{\"result\":"
							+ convertEntityToString(response.getEntity()) + "}";
					json = new JSONObject(getString);
					json.put("response", "success");
				} else {
					json = new JSONObject();
					json.put("response", "failed");
				}
			} else {
				json = new JSONObject();
				json.put("response", "failed");
			}

		return json;
	}
	
	public static Document getXML(String url) throws IllegalStateException, IOException {
		HttpClient httpClient = new DefaultHttpClient(getHttpParams(15000,
				15000));
		HttpResponse response = httpClient.execute(new HttpGet(url));
		return generateXmlFormIS(response.getEntity().getContent());
	}
	
	public static boolean isInternetAvailable(Context context) {
		ConnectivityManager cm = (ConnectivityManager) context
				.getSystemService(Context.CONNECTIVITY_SERVICE);
		if (cm.getActiveNetworkInfo() != null)
			return cm.getActiveNetworkInfo().isConnectedOrConnecting();
		else
			return false;
	}

	private static HttpParams getHttpParams(int connectionTimeout,
			int socketTimeout) {
		HttpParams params = new BasicHttpParams();

		HttpConnectionParams.setConnectionTimeout(params, connectionTimeout);
		HttpConnectionParams.setSoTimeout(params, socketTimeout);

		return params;
	}
	
	public static String convertEntityToString(HttpEntity entity) {
		InputStream instream;
		StringBuilder total = null;
		try {
			instream = entity.getContent();
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					instream));
			total = new StringBuilder();
			String line;
			while ((line = reader.readLine()) != null) {
				total.append(line);
			}
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return total.toString();
	}
	
	public static Document generateXmlFormIS(InputStream xml) {
		Document doc = null;
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			InputSource is = new InputSource();
			is.setByteStream(xml);
			doc = db.parse(is);
		} catch (ParserConfigurationException e) {
			System.out.println("XML parse error: " + e.getMessage());
			return null;
		} catch (SAXException e) {
			System.out.println("Wrong XML file structure: " + e.getMessage());
			return null;
		} catch (IOException e) {
			System.out.println("I/O exeption: " + e.getMessage());
			return null;
		}
		return doc;
	}
	
	private static String convertAnimeToXML(Anime anime) {
		String xml = new String();
		xml = "<entry>" +
					"<episode>" + anime.getWatchedEpisode() + "</episode>" +
					"<status>" + anime.getWathcedStatus() + "</status>" +
					"<score>" + anime.getScore() + "</score>" +
					"<downloaded_episodes>0</downloaded_episodes>" +
					"<storage_type>0</storage_type>" +
					"<storage_value>0.0</storage_value>" +
					"<times_rewatched>0</times_rewatched>" +
					"<rewatch_value>0</rewatch_value>" +
					"<date_start>" + anime.getStartDate() + "</date_start>" +
					"<date_finish>" + anime.getEndDate() + "</date_finish>" + 
					"<priority>" + anime.getPriority() + "</priority>" +
					"<enable_discussion>0</enable_discussion>" + 
					"<enable_rewatching>0</enable_rewatching>" +
					"<comments>" + anime.getComments() + "</comments>" +
					"<fansub_group></fansub_group>" +
					"<tags>" + anime.getTags() + "</tags>" +
				"</entry>";
		return xml;
	}
	
	private static String convertMangaToXML(Manga manga) {
		String xml = new String();
		xml = "<entry>" +
					"<chapter>" + manga.getChapterRead() + "</chapter>" +
					"<volume>" + manga.getVolumesRead() + "</volume>" +
					"<status>" + manga.getReadStatus() + "</status>" +
					"<score>" + manga.getScore() + "</score>" +
					"<downloaded_chapters>0</downloaded_chapters>" +
					"<times_reread>0</times_reread>" +
					"<reread_value>0</reread_value>" +
					"<date_start>" + manga.getStartDate() + "</date_start>" +
					"<date_finish>" + manga.getEndDate() + "</date_finish>" +
					"<priority>" + manga.getPriority() + "</priority>" + 
					"<enable_discussion>0</enable_discussion>" +
					"<enable_rereading>0</enable_rereading>" +
					"<comments>" + manga.getComments() + "</comments>" +
					"<scan_group></scan_group>" +
					"<tags>" + manga.getTags() + "</tags>" +
					"<retail_volumes>0</retail_volumes>" +
				"</entry>";
		return xml;
	}
}
